package utils;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author wrq
 * @version 1.0
 * @date 2020/9/2 17:55
 */
@Slf4j
public class FtpUtil {
    /**
     * FTP地址
     **/
    private static String ftpAddress;

    /**
     * FTP端口
     **/
    private static int ftpPort = 0;

    /**
     * FTP用户名
     **/
    private static String ftpUsername;

    /**
     * FTP密码
     **/
    private static String ftpPassword;

    /**
     * FTP基础目录
     **/
    private static String basePath = "/";

    private static String fileNameForXml = "";

    /**
     * 初始化登录ftp 默认false 登录成功返回true
     **/
    private static Boolean b = false;

    public static Boolean getB() {
        return b;
    }

    /**
     * 2018-6-13 12:39:55
     * 新添，初始化登录ftp，连接失败 返回b 为：false ,成功 为 ：true
     *
     * @param ftpUsername
     * @param ftpPassword
     * @param basePath
     */
    public FtpUtil(String ftpAddress, int ftpPort, String ftpUsername, String ftpPassword, String basePath) {
        FtpUtil.ftpAddress = ftpAddress;
        FtpUtil.ftpPort = ftpPort;
        FtpUtil.ftpUsername = ftpUsername;
        FtpUtil.ftpPassword = ftpPassword;
        FtpUtil.basePath = basePath;
        b = login(ftpAddress, ftpPort, this.ftpUsername, this.ftpPassword);
    }


    /**
     * 本地字符编码
     **/
    private static String localCharset = "GBK";

    /**
     * FTP协议里面，规定文件名编码为iso-8859-1
     **/
    private static String serverCharset = "ISO-8859-1";

    /**
     * UTF-8字符编码
     **/
    private static final String CHARSET_UTF8 = "UTF-8";

    /**
     * OPTS UTF8字符串常量
     **/
    private static final String OPTS_UTF8 = "OPTS UTF8";

    /**
     * 设置缓冲区大小
     **/
    private static final int BUFFER_SIZE = 1024 * 1024 * 10;

    /**
     * FTPClient对象
     **/
    private static FTPClient ftpClient = null;

    /**
     * 下载指定文件到本地
     *
     * @param ftpPath  FTP服务器文件相对路径，例如：test/123
     * @param fileName 要下载的文件名，例如：test.txt
     * @return 成功返回true，否则返回false
     */
    public static boolean downloadFile(String ftpPath, String fileName, String savePath) {
        // 登录
        boolean flag = false;
        FtpUtil ftpUtil = new FtpUtil(ftpAddress, ftpPort, ftpUsername, ftpPassword, ftpPath);
        Boolean b = ftpUtil.getB();
        if (b) {
            log.info("连接Ftp成功");
        }

        if (ftpClient != null) {
            try {
                String path = changeEncoding(ftpPath);
                // 判断是否存在该目录
                if (!ftpClient.changeWorkingDirectory(path)) {
                    log.error(ftpPath + "该目录不存在");
                    return flag;
                }
                ftpClient.enterLocalPassiveMode();  // 设置被动模式，开通一个端口来传输数据
                String[] fs = ftpClient.listNames();
                // 判断该目录下是否有文件
                if (fs == null || fs.length == 0) {
                    log.error(ftpPath + "该目录下没有文件");
                    return flag;
                }
                for (String ff : fs) {
                    String ftpName = new String(ff.getBytes("iso-8859-1"), "utf-8");
                    if (ftpName.equals(fileName)) {
                        File file = new File(savePath + "/" + ftpName);
                        //本地测试的打开
                        //File file = new File(savePath + "\\" + ftpName);
                        try {
                            OutputStream os = new FileOutputStream(file);
                            flag = ftpClient.retrieveFile(ff, os);
                        } catch (Exception e) {
                            log.error(e.getMessage(), e);
                        }
                        break;
                    }
                }
            } catch (IOException e) {
                log.error("下载文件失败", e);
            } finally {
                Boolean close = closeConnect();
                log.info("连接是否关闭：" + close);
            }
        }
        return flag;
    }

    /**
     * 连接FTP服务器
     *
     * @param address  地址，如：127.0.0.1
     * @param port     端口，如：21
     * @param username 用户名，如：root
     * @param password 密码，如：root
     */
    private Boolean login(String address, int port, String username, String password) {
        ftpClient = new FTPClient();
        try {
            ftpClient.connect(address, port);
            ftpClient.login(username, password);
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            int reply = ftpClient.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                closeConnect();
                log.error("FTP服务器连接失败：" + "地址：" + address + "  端口：" + port + "  用户名：" + username + "  密码：" + password);
            } else {
                b = true;
            }
        } catch (Exception e) {
            log.error("FTP登录失败", e);
        }
        return b;
    }

    /**
     * 获取路径下的所有文件全路径
     * @param path
     * @return
     */
    public static String[] listFilePath(String path) {
        ftpClient.enterLocalPassiveMode();
        String[] filePath = null;
        try {
            filePath = ftpClient.listNames(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return filePath;
    }

    /**
     * 获取路径下的所有文件
     * @param path
     * @return
     */
    public static FTPFile[] listFile(String path) {
        ftpClient.enterLocalPassiveMode();
        FTPFile[] files = null;
        try {
            files = ftpClient.listFiles(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return files;
    }

    /**
     * 移动文件（复制后删除）
     * @param filePath
     * @param savePath
     * @return
     */
    public static void mvFile(String filePath, String savePath) {
        File file = new File(filePath);
        try {
            OutputStream os = new FileOutputStream(file);
            boolean flag = ftpClient.retrieveFile(savePath + filePath, os);
            if (flag) {
                ftpClient.deleteFile(filePath);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void deleteFile(String filePath) {
        try {
            ftpClient.deleteFile(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 读取ftp中的文件内容
     * @param path
     * @param fileName
     * @return
     */
    public static String getFTPFile(String path, String fileName) {
        StringBuilder sb = new StringBuilder();
        try {
            ftpClient.changeWorkingDirectory(path);
            FTPFile[] files = ftpClient.listFiles();
            InputStream in = null;
            if (files.length > 0) {
                in = ftpClient.retrieveFileStream(fileName);
            }
            if (in != null) {
                BufferedReader br = new BufferedReader(new InputStreamReader(in, StandardCharsets.UTF_8));
                String data;
                while ((data = br.readLine()) != null) {
                    sb.append(data);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("FTP读取数据异常！");
        } finally {
            //关闭连接
            closeConnect();
        }
        return sb.toString();
    }

    /**
     * 获取ftp上指定文件名到输出流中
     *
     * @param ftpFileName
     * @param out
     * @throws IOException
     */
    public void retrieveFile(String ftpFileName, OutputStream out) throws IOException {
        try {
            FTPFile[] fileInfoArray = ftpClient.listFiles(ftpFileName);
            if (fileInfoArray == null || fileInfoArray.length == 0) {
                throw new FileNotFoundException("File '" + ftpFileName + "' was not found on FTP server.");
            }

            FTPFile fileInfo = fileInfoArray[0];
            if (fileInfo.getSize() > Integer.MAX_VALUE) {
                throw new IOException("File '" + ftpFileName + "' is too large.");
            }

            if (!ftpClient.retrieveFile(ftpFileName, out)) {
                throw new IOException("Error loading file '" + ftpFileName + "' from FTP server. Check FTP permissions and path.");
            }
            out.flush();
        } finally {
            closeStream(out);
        }
    }

    /**
     * 获取ftp上指定文件名到输出流中
     *
     * @param stream
     */
    private static void closeStream(Closeable stream) {
        if (stream != null) {
            try {
                stream.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    /**
     * 关闭FTP连接
     */
    public static Boolean closeConnect() {
        Boolean b = false;
        if (ftpClient != null && ftpClient.isConnected()) {
            try {
                ftpClient.logout();
                b = true;
            } catch (IOException e) {
                log.error("关闭FTP连接失败", e);
            }
        }
        return b;
    }

    /**
     * FTP服务器路径编码转换
     *
     * @param ftpPath FTP服务器路径
     * @return String
     */
    private static String changeEncoding(String ftpPath) {
        String directory = null;
        try {
            if (FTPReply.isPositiveCompletion(ftpClient.sendCommand(OPTS_UTF8, "ON"))) {
                localCharset = CHARSET_UTF8;
            }
            directory = new String(ftpPath.getBytes(CHARSET_UTF8), CHARSET_UTF8);
        } catch (Exception e) {
            log.error("路径编码转换失败", e);
        }
        return directory;
    }

    //创建文件夹
    public static String fileMkdir(String fileName, String ftpAddress, int ftpPort, String ftpUsername, String ftpPassword, String basePath) throws IOException {
        FtpUtil ftpUtil = new FtpUtil(ftpAddress, ftpPort, ftpUsername, ftpPassword, basePath);
        Boolean b = ftpUtil.getB();
        if (b) {
            log.info("连接Ftp成功");
        }
        //连接建立 创建文件夹
        String path = null;
        try {
            ftpClient.makeDirectory(fileName);
            path = changeEncoding("/" + fileName);
            if (!ftpClient.changeWorkingDirectory(path)) {
                fileMkdir(fileName, ftpAddress, ftpPort, ftpUsername, ftpPassword, basePath);
            } else {
                return path;
            }
        } catch (Exception e) {
            throw new RuntimeException("网络异常");
        } finally {
            if (b) {
                //关闭
                ftpUtil.closeConnect();
                log.info("Ftp连接关闭");
            }
            return path;
        }
    }

    //进行上传文件
    public static boolean uploadFile(String json, String fileName, String ftpAddress, int ftpPort, String ftpUsername, String ftpPassword, String basePath, String path) {
        // 创建的文件
        fileName = fileName + ".txt";
        boolean b = false;
        try {
            new FtpUtil(ftpAddress, ftpPort, ftpUsername, ftpPassword, basePath);
            InputStream is = null;
            // 1.输入流
            is = new ByteArrayInputStream(json.getBytes());
            // 4.指定写入的目录
            ftpClient.changeWorkingDirectory(path);
            // 5.写操作
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.setControlEncoding("UTF-8");
            ftpClient.enterLocalPassiveMode();//被动模式
            b = ftpClient.storeFile(new String(fileName.getBytes("utf-8"),
                    "iso-8859-1"), is);
            is.close();
            return b;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return b;
    }

    //进行上传文件
    public static String uploadFileBackPath(InputStream inputStream, String fileName, String ftpAddress, int ftpPort, String ftpUsername, String ftpPassword, String basePath, String path) {
        String filePath = null;
        StringBuffer stringBuffer = new StringBuffer();
        boolean b = false;
        try {
            new FtpUtil(ftpAddress, ftpPort, ftpUsername, ftpPassword, basePath);
            // 4.指定写入的目录
            ftpClient.changeWorkingDirectory(path);
            // 5.写操作
            ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftpClient.setControlEncoding("UTF-8");
            ftpClient.enterLocalPassiveMode();//被动模式
            b = ftpClient.storeFile(new String(fileName.getBytes("utf-8"),
                    "iso-8859-1"), inputStream);
            inputStream.close();
            if (b) {
                filePath = stringBuffer.append(path).append("/").append(fileName).toString();
            }
            return filePath;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}

